package org.tri.form;

import java.awt.Desktop;
import java.awt.Point;
import java.io.*;
import java.util.Date;
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.poi.ss.usermodel.*;

/**
 * La clase {@code Form} es la base para distintas forms que se generan sobre
 * templates .xls (hoja de cálculo de Exel) usando la API Apache POI.
 * Esta clase prevee un método para facilitar a las clases hijas setear valores
 * en diferentes celdas, ademas de guardar y abrirEImprimir el archivo generado.
 * @author kiira
 * @version 1.0, Jan 7, 2012
 */
public class Form {

    /** Nombre del template utilizado. */
    private String template;
    /** Archivo de entrada (Template). */
    private File fileIn;
    /** Archivo de salida. */
    private File fileOut;
    /** Workbook xls. */
    private Workbook wb;
    /** Hoja del workbook donde se escriben los valores. */
    private Sheet form;
    /** Extensión de las templates (.xls). */
    private final static String EXTENSION = ".xls";
    /** Path donde se guardan las templates. */
    private final static String TEMPLATE_PATH = "template/";
    /** Path donde se guardan los archivos completados. */
    private final static String OUTPUT_PATH = "output/";

    /**
     * Inicializa el form a partir de un template y de un archivo de salida que
     * es donde este form sera guardado cuando sea necesario.
     * @param template template a usar.
     * @param output nombre del archivo de salida.
     * @throws FileNotFoundException si no se encuentra el template en el 
     * directorio de templates.
     * @throws IOException si no se puede abrir el template.
     * @throws InvalidFormatException si el template es un archivo inválido.
     */
    public Form( String template, String output )
            throws FileNotFoundException, IOException, InvalidFormatException {
        this.template = template;

        //creamos los archivos
        fileIn = new File( TEMPLATE_PATH + template + EXTENSION );
        fileOut = new File( OUTPUT_PATH + output + " - "
                            + template + " - " + new Date() + EXTENSION );

        //abrimos y cargamos el template
        InputStream inp = new FileInputStream( fileIn );

        wb = WorkbookFactory.create( inp );
        form = wb.getSheetAt( 0 );

        wb.cloneSheet( 0 );

    }//end constructor

    /**
     * Setea un valor a una celda identificada por sus coordenadas x e y en
     * la hoja de calculo.
     * @param celda punto que indica la coordenada de la celda a modificar.
     * @param text valor a colocar en la celda.
     */
    protected void appendText( Point celda, String text ) {
        //obtenemos la celda afectada
        Row row = form.getRow( celda.y );
        Cell cell = row.getCell( celda.x );

        //apendamos el texto a la celda
        cell.setCellValue( cell.getStringCellValue() + text );

    }//end métdo appendText

    /**
     * Multiplica la altura de una fila en particular por el multiplicador
     * indicado, permitiendo asi que se vean mas lineas de la fila.
     * @param index fila a modificar.
     * @param multplicador multiplicador de altura.
     */
    protected void aumentarAlturaFila( int index, int multplicador ) {
        Row row = form.getRow( index );
        
        row.setHeight( (short)(row.getHeight() * multplicador) );
        
    }//end método aumentarAlturaFila
    
    /**
     * Cambia la hoja activa a la siguiente, generando una nueva hoja vacia
     * de ser necesario.
     */
    public void nextSheet() {
        //indice de la sigueinte sheet
        int index = wb.getSheetIndex( form ) + 1;
        //asignamos la siguiente sheet
        form = wb.getSheetAt( index );
        //y la clonamos para tener una hoja de resguardo si se necesita
        wb.cloneSheet( index );

    }//end método nextSheet

    /**
     * Guarda esta form en el archivo de salida indicado en el constructor.
     * @throws FileNotFoundException si el archivo existe pero es un directorio
     * o si por alguna razón no se puede crear el archivo.
     * @throws IOException si el archivo no se puede escribir.
     */
    public void guardar() throws FileNotFoundException, IOException {
        guardar( fileOut );

    }//end método guardar
    
    protected void guardar( File output ) throws FileNotFoundException,
                                                 IOException {        
        //oculatamos la ultima sheet que esta vacia
        wb.setSheetHidden( wb.getNumberOfSheets() - 1, true );

        FileOutputStream fos = null;

        try {
            //recreamos el archivo si ya existe o lo creamos si no
            if ( output.exists() )
                output.delete();
            
            output.createNewFile();
            
            //abrimos el stream y escribimos el archivo
            fos = new FileOutputStream( output );
            wb.write( fos );

        } finally {
            //cerramos el stream
            if ( fos != null )
                fos.close();

        }
        
        //hacemos visible la ultima sheet por si hace falta utilizarla
        wb.setSheetHidden( wb.getNumberOfSheets() - 1, false );
        
    }

    /**
     * Borra el archivo de salida.
     */
    public void borrar() {
        fileOut.delete();

    }//end método borar

    /**
     * Intenta abrir el archivo de salida con el programa por defecto utilizado
     * en el sistema operativo, e intenta abrir el dialog de impresión.
     * En caso de no poder abrir el dialog de impresión, simplemente abre el 
     * archivo.
     * @throws IOException si el archivo no se puede abrir, ya sea por que 
     * no se pudo generar el archivo temporal o por que no existe una aplicación
     * definida para abrir el tipo de archivo indicado (.xls)
     */
    public void abrirEImprimir() throws IOException {
        File file = File.createTempFile( template, EXTENSION );

        guardar( file );

        try {
            //intenta abrir para imprimir
            Desktop.getDesktop().print( file );

        } catch ( UnsupportedOperationException uOEx ) {
            //si no puede abrir para imprimir, intenta abrir solamente
            Desktop.getDesktop().open( file );

        }

    }//end método abrirEImprimir

}//end clase Form

